package M

import (
	"bytes"
	"crypto/md5"
	"crypto/rand"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"math/big"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"

	"github.com/skip2/go-qrcode"
)

var Server *TServer //全局服务器变量
/**
demo
go:embed testhtml //嵌入静态文件,testhtml 是文件名
var temp embed.FS
s := M.SERVER() //开启服务器
s.Efile=temp //设置嵌入目录
s.Embed=true //是否嵌入
s.GET("/cc/(id)", cc)
s.Static("/dede/","testhtml")
s.SessionStart()//开启session
s.Run("8080")
*/

func SERVER() *TServer {
	dir, _ := os.Getwd()
	Server = &TServer{
		public:  map[string]string{},
		embed:   false, //嵌入静态文件
		Ws:      map[string]*wsConnection{},
		SiteKey: "mtfy2021",
		Root:    dir,
	}
	return Server
}

//随机生成字符串
func RandStr(len int) string {
	var container string
	var str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
	b := bytes.NewBufferString(str)
	length := b.Len()
	bigInt := big.NewInt(int64(length))
	for i := 0; i < len; i++ {
		randomInt, _ := rand.Int(rand.Reader, bigInt)
		container += string(str[randomInt.Int64()])
	}
	return container
}
func GetMd5String(s string) string {
	h := md5.New()
	h.Write([]byte(s))
	return hex.EncodeToString(h.Sum(nil))
}
func Uid() string {
	b := make([]byte, 48)
	if _, err := io.ReadFull(rand.Reader, b); err != nil {
		return ""
	}
	return GetMd5String(base64.URLEncoding.EncodeToString(b))
}

//转换成字符串
func ToStr(v interface{}) string {
	var newStr string
	var ok bool
	switch v.(type) {
	case bool:
		if newV, ok := v.(bool); ok {
			return strconv.FormatBool(newV)
		}
	case string:
		if newStr, ok = v.(string); ok {
			return newStr
		}
	case int:
		if newV, ok := v.(int); ok {
			//转换成string
			newStr = strconv.Itoa(newV)
			return newStr
		}
	case int8:
		if newV, ok := v.(int8); ok {
			return strconv.FormatInt(int64(newV), 10)
		}
	case int16:
		if newV, ok := v.(int16); ok {
			return strconv.FormatInt(int64(newV), 10)
		}
	case int32:
		if newV, ok := v.(int32); ok {
			return strconv.FormatInt(int64(newV), 10)
		}
	case int64:
		if newV, ok := v.(int64); ok {
			return strconv.FormatInt(newV, 10)
		}
	case uint:
		if newV, ok := v.(uint); ok {
			return strconv.FormatUint(uint64(newV), 10)
		}
	case uint16:
		if newV, ok := v.(uint16); ok {
			return strconv.FormatUint(uint64(newV), 10)
		}
	case uint32:
		if newV, ok := v.(uint32); ok {
			return strconv.FormatUint(uint64(newV), 10)
		}
	case uint64:
		if newV, ok := v.(uint64); ok {
			return strconv.FormatUint(newV, 10)
		}
	case float32:
		if newV, ok := v.(float32); ok {
			return strconv.FormatFloat(float64(newV), 'f', -1, 64)
		}
	case float64:
		if newV, ok := v.(float64); ok {
			return strconv.FormatFloat(newV, 'f', -1, 64)
		}
	}
	return ""
}
func ToInt(v interface{}) int {
	//var nweInt int
	switch v.(type) {
	case int:
		if newI, ok := v.(int); ok {
			return newI
		}
	case int8:
		if newI, ok := v.(int8); ok {
			return int(newI)
		}
	case int16:
		if newI, ok := v.(int16); ok {
			return int(newI)
		}
	case int32:
		if newI, ok := v.(int32); ok {
			return int(newI)
		}
	case int64:
		if newI, ok := v.(int64); ok {
			return int(newI)
		}
	case uint:
		if newI, ok := v.(uint); ok {
			return int(newI)
		}
	case uint8:
		if newI, ok := v.(uint8); ok {
			return int(newI)
		}
	case uint16:
		if newI, ok := v.(uint16); ok {
			return int(newI)
		}
	case uint32:
		if newI, ok := v.(uint32); ok {
			return int(newI)
		}
	case uint64:
		if newI, ok := v.(uint64); ok {
			return int(newI)
		}
	case float32:
		if newI, ok := v.(float32); ok {
			return int(newI)
		}
	case float64:
		if newI, ok := v.(float64); ok {
			return int(newI)
		}
	case bool:
		if _, ok := v.(bool); ok {
			return 1
		} else {
			return 0
		}
	case string:
		if newI, ok := v.(string); ok {
			if newInt, err := strconv.Atoi(newI); err == nil {
				return newInt
			} else {
				return 0
			}
		}

	}

	return 0
}
func Md5(str string) string {
	data := []byte(str)
	has := md5.Sum(data)
	md5str := fmt.Sprintf("%x", has)
	return md5str
}
func Base64_Encode(str string) string {
	return base64.StdEncoding.EncodeToString([]byte(str))
}
func Base64_Decode(str string) string {
	sDec, _ := base64.StdEncoding.DecodeString(str)
	return string(sDec)
}

func Encode(str, key string) string {
	key = Md5(key)
	key_leng := len(key)
	var strlen int

	str = (Md5(str + key))[:8] + str
	strlen = len([]rune(str))

	var rndkey [256]int
	var box [256]int
	for i := 0; i <= 255; i++ {
		rndkey[i] = int(key[i%key_leng])
		box[i] = i
	}
	j := 0
	for i := 0; i < 256; i++ {
		j = (j + box[i] + rndkey[i]) % 256
		box[i], box[j] = box[j], box[i]
	}

	a := 0
	j = 0
	var rusult []byte
	for i := 0; i < strlen; i++ {
		a = (a + 1) % 256
		j = (j + box[a]) % 256
		box[a], box[j] = box[j], box[a]
		rusult = append(rusult, byte(ToInt(str[i])^(box[(box[a]+box[j])%256])))
	}
	retstr := string(rusult)
	retstr = Base64_Encode(retstr)
	retstr = strings.Replace(retstr, "=", "-04.-", -1)
	retstr = strings.Replace(retstr, "%", "-01.-", -1)
	retstr = strings.Replace(retstr, "/", "-02.-", -1)
	retstr = strings.Replace(retstr, "+", "-03.-", -1)
	return retstr
}
func Decode(str, key string) string {

	str = strings.Replace(str, "-01.-", "%", -1)
	str = strings.Replace(str, "-02.-", "/", -1)
	str = strings.Replace(str, "-03.-", "+", -1)
	str = strings.Replace(str, "-04.-", "=", -1)

	key = Md5(key)
	key_leng := len(key)
	var strlen int
	str = Base64_Decode(str)
	strlen = len([]byte(str))
	var rndkey [256]int
	var box [256]int
	for i := 0; i <= 255; i++ {
		rndkey[i] = int(key[i%key_leng])
		box[i] = i
	}
	j := 0
	for i := 0; i < 256; i++ {
		j = (j + box[i] + rndkey[i]) % 256
		box[i], box[j] = box[j], box[i]
	}
	a := 0
	j = 0
	var rusult []byte
	for i := 0; i < strlen; i++ {
		a = (a + 1) % 256
		j = (j + box[a]) % 256
		box[a], box[j] = box[j], box[a]
		rusult = append(rusult, byte(ToInt(str[i])^(box[(box[a]+box[j])%256])))
	}
	retstr := string(rusult)
	if len(retstr) < 8 {
		return ""
	}
	if retstr[0:8] == (Md5(retstr[8:] + key))[0:8] {
		return retstr[8:]
	} else {
		return ""
	}
}
func Json_Decode(str string, j interface{}) {
	err := json.Unmarshal([]byte(str), &j)
	if err == nil {
		j = nil
	}
}
func Json_Encode(j interface{}) string {
	context, err := json.Marshal(j)
	if err != nil {
		return ""
	} else {
		return string(context)
	}
}
func Url_Encode(u string) string {
	return url.QueryEscape(u)
}
func Url_Decode(u string) string {
	uu, err := url.QueryUnescape(u)
	if err != nil {
		return ""
	}
	return uu
}
func Url_Get(u string) (string, string) {
	res, err := http.Get(u)
	if err != nil {
		return "", "访问错误"
	}
	defer res.Body.Close()
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return "", "读取错误"
	}
	return string(body), ""
}
func Is_Path(path string) bool {
	_, err := os.Stat(path)
	if err == nil {
		return true
	}
	if os.IsNotExist(err) {
		return false
	}
	return false
}
func Qr_Creat(str string) string {
	q, err := qrcode.New(str, qrcode.Medium)
	if err != nil {
		return ""
	}
	rootpath, _ := os.Getwd()
	savePath := rootpath + "/cache/"
	if Is_Path(savePath) == false {
	_:
		os.MkdirAll(savePath, 0777)
	}
	file := savePath + RandStr(10) + ".png"
_:
	q.WriteFile(200, file)
	return file
}
